package com.xxxx.service.impl;

import com.xxxx.pojo.Order;
import com.xxxx.pojo.Product;
import com.xxxx.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * 订单服务 实现层
 */
@Service
public class OrderServiceImpl implements IOrderService {  // service 实现层

    @Autowired
    private RestTemplate restTemplate;  // 默认情况下是没有集成过来的，所以需要在 启动类 中通过@Bean注解添加一下

    // 元数据对象，从注册中心获取服务列表（根据服务名称获取具体的微服务，然后获取具体的url资源）
    @Autowired
    private DiscoveryClient discoveryClient;  // 导包的是 springframework 下的 DiscoveryClient

    @Autowired
    private LoadBalancerClient loadBalancerClient;  // Ribbon 负载均衡器，在org.springframework.cloud.client.loadbalancer.LoadBalancerClient;包下

    /**
     * 根据主键查询订单
     */
    @Override
    public Order selectOrderById(Integer id) {
        // 这里也是模拟了一下dao层从数据库中返回数据
//        return new Order(id, "order-001", "中国", 31994D, selectProductListByDiscoveryClient()); // 第一种实现方式 DiscoveryClients
        return new Order(id, "order-001", "中国", 31994D, selectProductListByLoadBalancerClient()); // 第二种实现方式 LoadBalancerClient  (使用负载均衡器的方式)
//        return new Order(id, "order-001", "中国", 31994D, selectProductListByLoadBalancerAnnotation()); // 第三种实现方式 @LoadBalanced 注解
    }

    /**
     * 第一种 实现方式 DiscoveryClients
     * <p>
     * 远程调用商品微服务，获取商品列表信息
     * <p>
     * 其中 DiscoveryClient 用来发现获取服务、RestTemplate 用来发送请求调用远程服务返回数据
     */
    private List<Product> selectProductListByDiscoveryClient() {

        StringBuffer sb = null;  // StringBuffer 线程安全的字符串拼接处理

        // 从注册中心 获取服务列表
        List<String> serviceIds = discoveryClient.getServices();
        if (CollectionUtils.isEmpty(serviceIds)) // 判断服务列表是否为空
            return null;

        // 根据 服务名称 获取服务，即获取服务名称为 service-provider 的服务
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances("service-provider");
        if (CollectionUtils.isEmpty(serviceInstances)) // 判断获取的服务是否为空
            return null;

        ServiceInstance si = serviceInstances.get(0); // 获取第一个服务实例

        sb = new StringBuffer();
        sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list");  // 拼接资源地址

        // ResponseEntity: 封装了返回数据
        ResponseEntity<List<Product>> response = restTemplate.exchange( // 通过 RestTemplate 发送请求调用获取资源
                sb.toString(), // 调用的远程地址
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {
                }
        );

        return response.getBody();
    }

    /**
     * 第二种 实现方式 LoadBalancerClient  (使用负载均衡器的方式)
     * <p>
     * 远程调用商品微服务，获取商品列表信息
     */
    private List<Product> selectProductListByLoadBalancerClient() {

        StringBuffer sb = null;  // 字符串拼接处理，使用 StringBuffer，线程安全的字符串拼接处理

        // 根据 服务名称 获取服务
        ServiceInstance si = loadBalancerClient.choose("service-provider");
        if (null == si) // 判空
            return null;

        sb = new StringBuffer();
        sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list");

        // 在这里打印一下获取的 服务提供者 的地址
        System.out.println("调用远程微服务的服务提供者地址是: " + sb.toString());

        // ResponseEntity: 封装了返回数据
        ResponseEntity<List<Product>> response = restTemplate.exchange(
                sb.toString(),
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {
                }
        );

        return response.getBody();
    }

    /**
     * 第三种 实现方式 @LoadBalanced 注解（这种方法常用）
     * <p>
     * 远程调用商品微服务，获取商品列表信息
     */
    private List<Product> selectProductListByLoadBalancerAnnotation() {
        // ResponseEntity: 封装了返回数据
        ResponseEntity<List<Product>> response = restTemplate.exchange(
                "http://service-provider/product/list",  // 注意这个 url 的地址写法
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {
                }
        );

        return response.getBody();
    }

}
